import {
  Component, OnInit, ElementRef, Output, EventEmitter, ContentChildren,
  QueryList, ViewChild, Input, AfterContentChecked, NgZone, AfterContentInit,
  Inject, Optional, ViewChildren, AfterViewChecked
} from '@angular/core';
import { NzModalService } from 'ng-zorro-antd';
import { NgForm } from '@angular/forms';

import { SelectFieldModalComponent } from './select-field-modal/select-field-modal.component';
import { FormItemComponent } from './form-item/form-item.component';
import { StoreService } from '../../core/service/store.service';
import { FORM_LABEL_INNER } from '../keys';
import { Base } from '../../core/view/base';
import { NavigationEnd } from '@angular/router';
import { FormCustomState } from '../../core/form-custom-state';

let formIndex = 0;

@Component({
  selector: 'bz-form',
  templateUrl: './form.component.html'
})
export class FormComponent<U, B, S> extends Base<U, B, S> implements OnInit, AfterContentChecked, AfterContentInit, AfterViewChecked {

  @Input() bzShowResetBtn = true;
  /** 表单类型 query 查询类型的表单 edit 编辑详情类型的表单 */
  @Input() bzType: 'query' | 'edit' = 'edit';
  /** 表单布局类型: inline-horizontal行内水平布局；inline-vertical行内垂直布局；horizontal水平布局 */
  @Input() set bzLayout(layout: 'inline-vertical' | 'inline-horizontal' | 'horizontal') {
    if (layout && layout.startsWith('inline-')) {
      this.formLayout = 'inline';
      this.isInlineHorizontal = layout === 'inline-horizontal';
    } else {
      this.formLayout = 'horizontal';
      this.isInlineHorizontal = false;
    }
    this._bzLayout = layout;
  }
  get bzLayout() {
    return this._bzLayout;
  }
  /** 每个表单项的间距 适用于行内布局 */
  @Input() bzGutter = 16;
  /** 表单描述文字水平对齐位置，适用于水平布局的表单 */
  @Input() bzLabelAlign: string;
  /** 表单描述文字的宽度，适用于水平布局的表单 */
  @Input() set bzLabelSpan(span) {
    if (this._bzLayout === 'horizontal') {
      this._labelSpan = span;
    }
  }
  get bzLabelSpan() {
    if (this._bzLayout === 'horizontal') {
      return this._labelSpan;
    }
  }

  /** 表单项的宽度，适用于水平布局的表单 */
  @Input() set bzFormItemSpan(span) {
    if (this._bzLayout === 'horizontal') {
      this._formItemSpan = span;
    }
  }
  get bzFormItemSpan() {
    if (this._bzLayout === 'horizontal') {
      return this._formItemSpan;
    }
  }
  get bzValidateForm() {
    return this._form && this._form.form;
  }

  /** 当前表单是否有效 */
  get isValid() {
    const keys = Object.keys(this._validator);
    for (let i = 0; i < keys.length; i++) {
      if (this._validator[keys[i]]) {
        return false;
      }
    }

    const formItemList = this.formItemList.toArray();
    let valid = true;
    for (let i = 0; i < formItemList.length; i++) {
      const formItem = formItemList[i];
      formItem.touched = true;
      formItem.validate();
      if (formItem.errorType) {
        valid = false;
      }
    }

    return valid;
  }

  /** 查询类表单默认最多显示多少行 */
  @Input() defaultShowLineCount = 2;
  /** 当该字段有值同时表单内的各个表单项的bzName也有值时会触发自动保存表单项显示状态到SessionStorage的功能 */
  @Input() bzName: string;
  /** 是否通过接口保存表单项显示状态，前提是满足自动保存到SessionStorage */
  @Input() bzSaveFormState = true;
  /** 表单label嵌入表格框中 */
  @Input() bzLabelInner = false;
  /** 点击查询按钮的事件回调，适用于查询类型的表单 */
  @Output() bzQuery = new EventEmitter();
  /** 点击重置按钮的事件回调，适用于查询类型的表单 */
  @Output() bzReset = new EventEmitter();

  @ContentChildren(FormItemComponent) formItemList: QueryList<FormItemComponent<U, B, S>>;
  @ViewChild('form', { static: true }) _form: NgForm;
  @ViewChildren('innerFormItem', { read: ElementRef }) innerFormItemElementList: QueryList<any>;
  @ViewChildren('innerFormItem') innerFormItemInstanceList: QueryList<any>;

  formIndex: number;
  nativeElement: Element;
  submitting = false;
  actionSpan = 6;
  isShowForm = true;
  isInlineHorizontal = true;
  formLayout = 'inline';

  private _validator = {};
  private _labelSpan = 6;
  private _formItemSpan = 12;
  /** 用户是否点击更多，选择过其他字段显示 */
  private _customField = false;
  /** 页面高度小于一定高度后强制显示一行数据，该变量表示是否处于强制显示一行数据的状态 */
  private _minDefaultShowLineCount = false;
  /** 页面高度小于一定高度后强制显示一行数据，该变量表示height最小临界值 */
  private _minHeightForDefaultShowLineCount = 700;
  // 'inline-horizontal' | 'horizontal' | 'inline-vertical'
  private _bzLayout: 'inline-vertical' | 'inline-horizontal' | 'horizontal';
  /** 将数据临时保存在sessionStorage中，避免频繁请求接口 */
  private formStatePrefix = 'CUSTOM_FORM_';

  private _defaultItemSpan = 6;
  /** 控制表单三列布局的阀值 */
  private _smallItemSpanMaxFormWidth = 1336;
  private _defaultItemSpanChangeTimeoutId;

  constructor(
    private elementRef: ElementRef,
    private modalService: NzModalService,
    @Inject(FORM_LABEL_INNER) @Optional() private labelInnerConfig = false,
    @Optional() private formCustomState: FormCustomState
  ) {
    super();
    this.bzLabelInner = labelInnerConfig;
  }

  ngAfterViewChecked(): void {
    if (this.innerFormItemElementList.length === 0 || this.innerFormItemInstanceList.length === 0) {
      return;
    }

    const innerElementList = [];
    const innerInstanceList = [];
    this.innerFormItemElementList.forEach((item, index) => {
      if (!item.nativeElement || !item.nativeElement.id) {
        return;
      }

      innerElementList.push(item);
      innerInstanceList.push((this.innerFormItemInstanceList as any)._results[index]);
    });

    this.formItemList.forEach((formItem) => {
      if (!formItem.bzName) {
        return;
      }

      const index = innerElementList.findIndex((item) => {
        return item.nativeElement.id === formItem.bzName;
      });

      if (index > -1) {
        formItem.innerElement = innerElementList[index].nativeElement;
        formItem.innerInstance = innerInstanceList[index];
      }
    });
  }

  getSpan(defaultValue) {
    if (!!this._bzLayout && this._bzLayout !== 'inline-vertical' && this._bzLayout !== 'inline-horizontal') {
      return 24;
    } else {
      return defaultValue || this._defaultItemSpan;
    }
  }

  ngOnInit() {
    formIndex++;
    this.formIndex = formIndex;
    this.nativeElement = this.elementRef.nativeElement;

    this.ngZone.runOutsideAngular(() => {
      setTimeout(() => {
        this.setDefaultShowLineCount();
        this.calcItemSpan();
      }, 500);
      window.addEventListener('resize', () => {
        this.setDefaultShowLineCount();
        this.calcItemSpan();
      });
      this.broadcastService.subscribe(<any>'AsideCollapsed', () => {
        setTimeout(() => {
          this.setDefaultShowLineCount();
          this.calcItemSpan();
        }, 300);
      });
      this.router.events.subscribe(e => {
        if (!(e instanceof NavigationEnd)) {
          return;
        }

        this.setDefaultShowLineCount();
        this.calcItemSpan();
      });
    });
  }

  /** 每次content变化都动态监测每个表单项的宽度 */
  ngAfterContentChecked(): void {
    if (this.bzType === 'query') {
      const _defaultShowLineCount = this._minDefaultShowLineCount ? 1 : this.defaultShowLineCount;

      const spanSum = this.formItemList.reduce((sum, item) => {
        const itemSpan = item.bzSpan || this._defaultItemSpan;
        item.defaultShow = undefined;
        if (item.getShow()) {
          if (!this._customField && sum + itemSpan + itemSpan > 24 * _defaultShowLineCount) {
            item.defaultShow = false;
          } else {
            sum += itemSpan;
          }
        }
        return sum;
      }, 0);
      this.actionSpan = 24 - spanSum % 24;
    } else {
      this.formItemList.reduce((sum, item) => {
        const itemSpan = item.bzSpan || this._defaultItemSpan;
        if (item.getShow() && item.bzLineBreak) {
          item.lineBreakOffset = 24 - sum % 24;
          item.lineBreakOffset = item.lineBreakOffset === 24 ? 0 : item.lineBreakOffset;
          // item.bzOffset = 0;
        }
        return sum += item.getShow() ? item.bzOffset + itemSpan + item.lineBreakOffset : 0;
      }, 0);
    }

  }

  onQuery() {
    this.bzQuery.emit();
  }

  setValidator(key, value) {
    this._validator[key] = value;
  }

  showFieldModal() {
    this.modalService.create({
      nzComponentParams: {
        fields: this.formItemList.filter(formItem => formItem.bzShow !== false)
      },
      nzContent: SelectFieldModalComponent,
      nzOnOk: (instance) => {
        this._customField = true;
        const formState = [];
        // 如果表单bzName不为空，并且表单项bzName不为空，则可以保存到sessionStorage中
        let saveSessionStorage = !!this.bzName;

        this.formItemList.forEach((item: any) => {
          if (item.customShow) {
            if (item.bzName) {
              formState.push(item.bzName);
            } else {// 统计是否所有customShow为true时都有bzName属性，如果没有，则取消默认保存状态的功能
              saveSessionStorage = false;
            }
          } else {
            item.setValue(undefined);
          }
        });

        // 保存到sessionStorage之后如果formState不为空，则尝试通过接口保存到后台
        if (saveSessionStorage && formState.length > 0) {
          const key = `${this.currPath()}||${this.bzName}`;
          const sessionStorekey = `${this.formStatePrefix}||${key}`;
          this.storeService.setItemByUID(<any>sessionStorekey, formState, true);
          // 通过接口保存数据
          if (this.bzSaveFormState && this.formCustomState) {
            this.formCustomState.saveFormState(key, formState);
          }
        } else {
          this.loggerService.warn('Unable to auto save form state');
        }
      }
    });
  }

  formRest() {
    let stopDefault = false;
    this.bzReset.emit({
      defaultPrevented: () => {
        stopDefault = true;
      }
    });
    if (!stopDefault) {
      this.formItemList.forEach((item) => {
        item.resetValue();
      });
    }
  }

  setDefaultShowLineCount() {
    if (this._customField) {
      return;
    }
    if ((this._minDefaultShowLineCount && document.body.clientHeight > this._minHeightForDefaultShowLineCount)
      || (!this._minDefaultShowLineCount && document.body.clientHeight < this._minHeightForDefaultShowLineCount)) {
      this.ngZone.run(() => {
        this._minDefaultShowLineCount = !this._minDefaultShowLineCount;
      });
    }
  }

  calcItemSpan() {
    const itemSpan = this.elementRef.nativeElement.clientWidth > this._smallItemSpanMaxFormWidth ? 6 : 8;
    if (itemSpan !== this._defaultItemSpan) {
      clearTimeout(this._defaultItemSpanChangeTimeoutId);
      this._defaultItemSpanChangeTimeoutId = setTimeout(() => {
        this.ngZone.run(() => {
          this._defaultItemSpan = itemSpan;
        });
      }, 300);
    }
  }

  ngAfterContentInit(): void {
    if (this.bzType === 'query') {
      this.loadFormState();
    }
  }

  formItemtrackBy(index, item: FormItemComponent<U, B, S>) {
    return item.bzName || item.bzLabel;
  }

  private loadFormState() {
    if (!this.bzName || this.formItemList.some(item => !item.bzName)) {
      if (this.bzSaveFormState && this.formCustomState) {
        this.loggerService.warn('bzName of BzForm is require when bzSaveItemState = true', 'FormComponent');
      }
      return;
    }

    new Promise((resolve, reject) => {
      const key = `${this.currPath()}||${this.bzName}`;
      const sessionStorekey = `${this.formStatePrefix}||${key}`;
      // 首先从sessionStorage中读取表单查询项数据，如果找不到才会从后台获取数据
      const formState = this.storeService.getItemByUID(<any>sessionStorekey, true);
      // 优先考虑sessionStorage中的数据
      if (formState && formState.length > 0) {
        resolve(formState);
      } else if (this.bzSaveFormState && this.formCustomState) {// 通过接口保存数据
        this.formCustomState.fetchFormState(key).then((list) => {
          this.storeService.setItemByUID(<any>sessionStorekey, list, true);
          resolve(list);
        });
      }
    }).then((data: any[]) => {
      if (!Array.isArray(data) || data.length <= 0) {
        return;
      }

      this._customField = true;
      this.formItemList.forEach((formItem) => {
        if (data.indexOf(formItem.bzName) === -1) {
          formItem.customShow = false;
        }
      });
    });
  }
}
